/**
 * 
 */
package com.gragra.functionalIdentification;
import it.unimi.dsi.fastutil.doubles.Double2ObjectRBTreeMap;
import it.unimi.dsi.fastutil.doubles.Double2ObjectSortedMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntCollection;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import com.gragra.frameStatistics.CoOccurrenceStatistics;
import com.gragra.frameStatistics.StatisticsGenerator;
import com.gragra.nounIdentification.Scorer;
/**
 * @author Christoph Teichmann
 * created Mar 26, 2013 7:00:45 PM
 * @version 0.1
 */
public class LowTypeTokenScorer implements Scorer
{
	/**
	 * the map used for storing and sorting weighting results
	 */
	private final Double2ObjectSortedMap<IntArrayList> sorter = new Double2ObjectRBTreeMap<IntArrayList>();
	/**
	 * 
	 */
	private final IntList il = new IntArrayList();
	/* (non-Javadoc)
	 * @see com.gragra.nounIdentification.Scorer#sortWords(it.unimi.dsi.fastutil.ints.IntCollection, com.gragra.frameStatistics.StatisticsGenerator, it.unimi.dsi.fastutil.ints.IntSet, int)
	 */
	@Override
	public IntList sortWords(IntCollection allWords,
			StatisticsGenerator sG, IntSet restriction,
			int iteration)
	{
		sorter.clear();
		CoOccurrenceStatistics cos = (CoOccurrenceStatistics) sG;
		IntIterator iit = allWords.iterator();
		addToSorter(cos, iit);
		return sort();
	}
	/**
	 * @param cos
	 * @param iit
	 * @param sorter2 
	 */
	protected void addToSorter(CoOccurrenceStatistics cos, IntIterator iit)
	{
		while(iit.hasNext())
		{
			int word = iit.nextInt();
			IntIterator is = cos.getFollowers(word).iterator();
			double entRight = 0.0;
			double wordC = cos.getWordCount(word);
			double logWC = Math.log(wordC);
			while(is.hasNext())
			{
				int co = is.nextInt();
				double am = cos.getForwardCoCount(word, co);
				entRight += am*(Math.log(am)-logWC);
			}
			entRight /= wordC;
			double entLeft = 0.0;
			is = cos.getPrecedents(word).iterator();
			while(is.hasNext())
			{
				int co = is.nextInt();
				double am = cos.getBackwardCoCount(word, co);
				entLeft += am*(Math.log(am)-logWC);
			}
			entLeft /= wordC;
			this.putIntoMap(word, entRight+entLeft);
		}
	}
	/* (non-Javadoc)
	 * @see com.gragra.nounIdentification.Scorer#sortFrames(it.unimi.dsi.fastutil.ints.IntCollection, com.gragra.frameStatistics.StatisticsGenerator, it.unimi.dsi.fastutil.ints.IntSet, int)
	 */
	@Override
	public IntList sortFrames(IntCollection allFrames, StatisticsGenerator sg,
			IntSet restriction, int iteration)
	{
		if(iteration == 0)
		{
			il.clear();
			return il;
		}
		sorter.clear();
		IntIterator iit = allFrames.iterator();
		while(iit.hasNext())
		{
			int frame = iit.nextInt();
			IntIterator wii = sg.getCoOccurringWords(frame).iterator();
			double val = 0.0;
			while(wii.hasNext())
			{
				int word = wii.nextInt();
				val += restriction.contains(word) ? 0.0 : 1.0;
			}
			this.putIntoMap(frame, -(val/sg.getFrameFrequency(frame)));
		}
		return sort();
	}
	/**
	 * used to feed the values from the map into the list
	 * @return
	 */
	private IntList sort()
	{
		il.clear();
		ObjectIterator<IntArrayList> iit = sorter.values().iterator();
		while(iit.hasNext())
		{
			IntArrayList ial = iit.next();
			for(int i=0;i<ial.size();++i)
			{il.add(ial.get(i));}
		}
		return il;
	}
	/**
	 * this method adds the given key to the map used for sorting with the given value
	 * @param key
	 * @param val
	 */
	protected void putIntoMap(int key, double val)
	{
		IntArrayList ial = this.sorter.get(val);
		if(ial == null)
		{
			ial = new IntArrayList();
			this.sorter.put(val, ial);
		}
		ial.add(key);
	}
}